package com.example.lottery_system.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.example.lottery_system.common.errorcode.ServiceErrorCodeConstants;
import com.example.lottery_system.common.exception.ServiceException;
import com.example.lottery_system.common.utiils.JWTUtil;
import com.example.lottery_system.common.utiils.RegexUtil;
import com.example.lottery_system.controller.param.ShortMessageLoginParam;
import com.example.lottery_system.controller.param.UserLoginParam;
import com.example.lottery_system.controller.param.UserPasswordLoginParam;
import com.example.lottery_system.controller.param.UserRegisterParam;
import com.example.lottery_system.dao.dataobject.Encrypt;
import com.example.lottery_system.dao.dataobject.UserDO;
import com.example.lottery_system.dao.mapper.UserMapper;
import com.example.lottery_system.service.UserService;
import com.example.lottery_system.service.dto.UserLoginDTO;
import com.example.lottery_system.service.dto.UserRegisterDTO;
import com.example.lottery_system.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationServiceImpl verificationService;
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //对注册信息进行检验
        checkUserRegisterInfo(param);
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getUserName());
        userDO.setEmail(param.getEmail());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentify());
        if (StringUtils.hasText(param.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }
        userMapper.insert(userDO);
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam userLoginParam) {
        UserLoginDTO userLoginDTO = null;
        if (userLoginParam instanceof UserPasswordLoginParam userPasswordLoginParam) {
            userLoginDTO = loginByPassword(userPasswordLoginParam);
        }else if (userLoginParam instanceof ShortMessageLoginParam shortMessageLoginParam) {
            userLoginDTO = loginByShortMessage(shortMessageLoginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        return userLoginDTO;
    }

    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam shortMessageLoginParam) {
        String phoneNumber = shortMessageLoginParam.getPhoneNumber();
        if (!RegexUtil.checkMobile(phoneNumber)) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(phoneNumber));
        if (null == phoneNumber) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }else if (StringUtils.hasText(shortMessageLoginParam.getMandatoryIdentity())
                    && !userDO.getIdentity().equals(shortMessageLoginParam.getMandatoryIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        String code = verificationService.getVerificationCode(phoneNumber);
        if (!shortMessageLoginParam.getCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //用户登录成功，构造token并且返回
        Map<String,Object> claims = new HashMap<>();
        claims.put("userId",userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claims);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(userDO.getIdentity());
        return userLoginDTO;
    }

    private UserLoginDTO loginByPassword(UserPasswordLoginParam userPasswordLoginParam) {
        String loginName = userPasswordLoginParam.getLoginName();
        String password = userPasswordLoginParam.getPassword();
        UserDO userDO = null;
        if (!StringUtils.hasText(password)) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        if (RegexUtil.checkMobile(loginName)) {
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginName));
        }else if (RegexUtil.checkMail(loginName)){
            userDO = userMapper.selectByEmail(loginName);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_OR_PHONE_ERROR);
        }
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST);
        }else if (StringUtils.hasText(userPasswordLoginParam.getMandatoryIdentity())
                    && !userPasswordLoginParam.getMandatoryIdentity().equals(userDO.getIdentity())){
            //看强制登陆的身份是否符合
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if (!userDO.getPassword().equals(DigestUtil.sha256Hex(password))) {
            //验证密码的正确性
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //用户登录成功，构造token并且返回
        Map<String,Object> claims = new HashMap<>();
        claims.put("userId",userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claims);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(userDO.getIdentity());
        return userLoginDTO;
    }

    private void checkUserRegisterInfo(UserRegisterParam param) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        //校验邮箱格式
        if (!RegexUtil.checkMail(param.getEmail())) {
            throw  new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //校验手机号码格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //校验身份信息
        if (null == UserIdentityEnum.forName(param.getIdentify())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验当身份为管理员的时候，是否有密码
        if (UserIdentityEnum.ADMIN.name().equals(param.getIdentify())
        && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //校验密码格式
        if (StringUtils.hasText(param.getPassword())
        && !RegexUtil.checkPassword(param.getPassword())) {
            throw  new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //校验邮箱是否被使用
        if (checkEmailUsed(param.getEmail())) {
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_USED);
        }
        //检查电话号码是否被使用
        if (checkPhoneNumberUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        return userMapper.countByPhoneNumber(new Encrypt(phoneNumber)) > 0;
    }

    private boolean checkEmailUsed(String email) {
        return userMapper.countByEmail(email) > 0;
    }
}
